package iit.projects.etaxi.view.bean;

import iit.projects.etaxi.model.dto.CitySCDO;
import iit.projects.etaxi.model.entity.City;
import iit.projects.etaxi.model.entity.Customer;
import iit.projects.etaxi.model.entity.Reservation;
import iit.projects.etaxi.model.entity.SubCity;
import iit.projects.etaxi.model.service.CityService;
import iit.projects.etaxi.model.service.ReservationService;
import iit.projects.etaxi.model.service.ServiceLocator;
import iit.projects.etaxi.model.service.SmsService;
import iit.projects.etaxi.util.Constants;
import iit.projects.etaxi.util.JSFUtils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;

import javax.faces.component.UIInput;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;

import com.icesoft.faces.component.ext.HtmlInputText;
import com.icesoft.faces.component.ext.HtmlInputTextarea;
import com.icesoft.faces.component.ext.HtmlSelectOneMenu;
import com.icesoft.faces.component.ext.HtmlSelectOneRadio;
import com.icesoft.faces.component.selectinputdate.SelectInputDate;

public class ReservationBackingBean {
	
	private Reservation reservation;
	private String fromSubCode;
	private String toSubCode;
	private boolean fromCitySelected;
	private boolean toCitySelected;
	private Date reservationDate;
	private boolean am;
	private int selHours;
	private int selMins;
	
	private List<City> cityList;
	private List<SelectItem> citySelectItemList;
	private List<SubCity> fromSubCityList;
	private List<SelectItem> fromSubCitySelectItemList;
	private List<SubCity> toSubCityList;
	private List<SelectItem> toSubCitySelectItemList;
	private List<SelectItem> hoursSelectItemList;
	private List<SelectItem> minsSelectItemList;
	
	private HtmlInputText compReservationCode;
	private HtmlInputTextarea compPickupAddress;
	private HtmlSelectOneMenu compType;
	private HtmlSelectOneMenu compFCity;
	private HtmlSelectOneMenu compTCity;
	private HtmlSelectOneMenu compFSCity;
	private HtmlSelectOneMenu compTSCity;
	private SelectInputDate compPickupDate;
	private HtmlSelectOneMenu compHrs;
	private HtmlSelectOneMenu compMins;
	private HtmlSelectOneRadio compAmPm;
	private HtmlSelectOneMenu compSeats;
	private HtmlSelectOneMenu compLuggages;
	private HtmlInputText compCustomerName;
	private HtmlInputText compCustomerContact;
	
	private ServiceLocator serviceLocator;
	private ReservationService reservationService;
	private CityService cityService;
	
	@javax.annotation.PostConstruct
	public void init(){
		reservationService = serviceLocator.getReservationService();
		cityService = serviceLocator.getCityService();
		
		reservation = new Reservation();
		loadCityData();
		loadHoursAndMins();
		
		fromSubCitySelectItemList = new ArrayList<SelectItem>();
		fromSubCitySelectItemList.add(new SelectItem(Constants.SELECT_VALUE, Constants.SELECT_LABEL));
		
		toSubCitySelectItemList = new ArrayList<SelectItem>();
		toSubCitySelectItemList.add(new SelectItem(Constants.SELECT_VALUE, Constants.SELECT_LABEL));
	}
	
	public void processReservations(ActionEvent event){
		reservationService.processReservations();
	}
	
	public void processReplies(ActionEvent event){
		SmsService smsService = serviceLocator.getSmsService();
		smsService.processSms();
	}
	
	public void valueChangeFromCity(ValueChangeEvent event){
		String cityCode = (String)event.getNewValue();
		clearFromSubCityList();
		if(cityCode != null){
			City city = findCityByCode(cityCode);
			fromSubCityList = new ArrayList<SubCity>(city.getSubcities());
			
			if(!fromSubCityList.isEmpty()){
				for(SubCity subCity : fromSubCityList){
					fromSubCitySelectItemList.add(new SelectItem(subCity.getCode(), subCity.getName()));
				}
			}
			fromCitySelected = true;
		}
		else{
			fromCitySelected = false;
		}
		
	}
	
	public void valueChangeToCity(ValueChangeEvent event){
		String cityCode = (String)event.getNewValue();
		clearToSubCityList();
		
		if(cityCode != null){
			City city = findCityByCode(cityCode);
			toSubCityList = new ArrayList<SubCity>(city.getSubcities());

			if(!toSubCityList.isEmpty()){
				for(SubCity subCity : toSubCityList){
					toSubCitySelectItemList.add(new SelectItem(subCity.getCode(), subCity.getName()));
				}
			}
			toCitySelected = true;
		}
		else{
			toCitySelected = false;
		}
	}
	
	private void clearFromSubCityList(){
		fromSubCitySelectItemList.clear();
		fromSubCitySelectItemList.add(new SelectItem(Constants.SELECT_VALUE, Constants.SELECT_LABEL));
	}
	
	private void clearToSubCityList(){
		toSubCitySelectItemList.clear();
		toSubCitySelectItemList.add(new SelectItem(Constants.SELECT_VALUE, Constants.SELECT_LABEL));
	}
	
	private City findCityByCode(String code){
		if(cityList != null && !cityList.isEmpty()){
			for(City city : cityList){
				if(city.getCode().equals(code)){
					return city;
				}
			}
		}
		return null;
	}
	
	private SubCity findFromSubCityByCode(String code){
		if(fromSubCityList != null && !fromSubCityList.isEmpty()){
			for(SubCity subCity : fromSubCityList){
				if(subCity.getCode().equals(code)){
					return subCity;
				}
			}
		}
		return null;
	}
	
	private SubCity findToSubCityByCode(String code){
		if(toSubCityList != null && !toSubCityList.isEmpty()){
			for(SubCity subCity : toSubCityList){
				if(subCity.getCode().equals(code)){
					return subCity;
				}
			}
		}
		return null;
	}
	
	private void loadCityData(){
		CitySCDO citySCDO = new CitySCDO();
		
		try{
			//Find all cities
			cityList = cityService.findCities(citySCDO);
		}catch(Throwable e){
			return;
		}
		
		citySelectItemList = new ArrayList<SelectItem>();
		citySelectItemList.add(new SelectItem(Constants.SELECT_VALUE, Constants.SELECT_LABEL));
		
		if(cityList != null && !cityList.isEmpty()){
			for(City city : cityList){
				citySelectItemList.add(new SelectItem(city.getCode(), city.getName()));
			}
		}
	}
	
	private void loadHoursAndMins(){
		hoursSelectItemList = new ArrayList<SelectItem>();
		minsSelectItemList = new ArrayList<SelectItem>();
		
		for(int i=1; i<=12; i++){
			String label = (i < 10)?"0" + new Integer(i).toString() : new Integer(i).toString();
			hoursSelectItemList.add(new SelectItem(new Integer(i),label));
		}
		
		for(int i=0; i<60; i+=15){
			String label = (i < 10)?"0" + new Integer(i).toString() : new Integer(i).toString();
			minsSelectItemList.add(new SelectItem(new Integer(i),label));
		}
	}
	
	public void save(ActionEvent event){
		
		if(!valid()){
			return;
		}
		
		SubCity fromSubCity = findFromSubCityByCode(fromSubCode);
		SubCity toSubCity = findToSubCityByCode(toSubCode);
		
		Calendar calendar = new GregorianCalendar();
		calendar.setTime(reservationDate);
		calendar.set(Calendar.HOUR, (am)? (selHours == 12)? 0 : selHours : (selHours == 12)? selHours : 12 + selHours);
		calendar.set(Calendar.MINUTE, selMins);
		calendar.setTimeZone(TimeZone.getDefault());
		
		reservation.setFromSubCity(fromSubCity);
		reservation.setToSubCity(toSubCity);
		reservation.setPickUpTime(calendar.getTime());
		if(reservation.getPickUpTime().before(new Date())){
			JSFUtils.addFacesErrorMessage(compPickupDate, "reservation.passReservationDate");
			return;
		}
		reservation.setStatus(Constants.ReservationStatus.NEW);
		
		if(JSFUtils.getFromSession(Constants.LOGGED_IN_AS_CUSTOMER) != null){
			Customer customer = (Customer)JSFUtils.getFromSession(Constants.CUSTOMER);
			reservation.setCustomer(customer);
			reservation.setCustomerName(customer.getFirstName());
			reservation.setCustomerContact(customer.getMobileNumber());
		}
		
		try{
			Reservation savedReservation = reservationService.createReservation(reservation);
			JSFUtils.addFacesInfoMessage("reservation.successfull", new String[]{savedReservation.getCode()});
			clear(event);
		}catch(Throwable e){
			return;
		}
	}
	
	public void clear(ActionEvent event){
		this.reservation = new Reservation();
		this.selHours = 1;
		this.selMins = 0;
		this.reservationDate = null;
		this.fromCitySelected = false;
		this.toCitySelected = false;
		compFCity.setValue(null);
		this.compTCity.setValue(null);
		this.am = false;
		
		clearFromSubCityList();
		clearToSubCityList();
		
		resetValues();
	}
	
	private void resetValues(){
		compReservationCode.resetValue();
		compPickupAddress.resetValue();
		compType.resetValue();
		compFCity.resetValue();
		compTCity.resetValue();
		compFSCity.resetValue();
		compTSCity.resetValue();
		compPickupDate.resetValue();
		compHrs.resetValue();
		compMins.resetValue();
		compSeats.resetValue();
		compLuggages.resetValue();
		compAmPm.resetValue();
		
		if(compCustomerName != null){
			compCustomerName.resetValue();
		}
		if(compCustomerContact != null){
			compCustomerContact.resetValue();
		}
	}
	
	private boolean valid(){
		boolean valid = true;
		
		if(compFCity.getValue() == null){
			JSFUtils.addFacesErrorMessage(compFCity, UIInput.REQUIRED_MESSAGE_ID);
			valid = false;
		}
		if(compTCity.getValue() == null){
			JSFUtils.addFacesErrorMessage(compTCity, UIInput.REQUIRED_MESSAGE_ID);
			valid = false;
		}
		if(fromSubCode == null){
			JSFUtils.addFacesErrorMessage(compFSCity, UIInput.REQUIRED_MESSAGE_ID);
			valid = false;
		}
		if(toSubCode == null){
			JSFUtils.addFacesErrorMessage(compTSCity, UIInput.REQUIRED_MESSAGE_ID);
			valid = false;
		}
		if(reservation.getPickupAddress() == null || reservation.getPickupAddress().isEmpty()){
			JSFUtils.addFacesErrorMessage(compPickupAddress, UIInput.REQUIRED_MESSAGE_ID);
			valid = false;
		}
		if(reservationDate == null){
			JSFUtils.addFacesErrorMessage(compPickupDate, UIInput.REQUIRED_MESSAGE_ID);
			valid = false;
		}
		
		return valid;
	}

	public void setServiceLocator(ServiceLocator serviceLocator) {
		this.serviceLocator = serviceLocator;
	}

	public Reservation getReservation() {
		return reservation;
	}

	public void setReservation(Reservation reservation) {
		this.reservation = reservation;
	}

	public String getFromSubCode() {
		return fromSubCode;
	}

	public void setFromSubCode(String fromSubCode) {
		this.fromSubCode = fromSubCode;
	}

	public String getToSubCode() {
		return toSubCode;
	}

	public void setToSubCode(String toSubCode) {
		this.toSubCode = toSubCode;
	}

	public boolean isFromCitySelected() {
		return fromCitySelected;
	}

	public void setFromCitySelected(boolean fromCitySelected) {
		this.fromCitySelected = fromCitySelected;
	}

	public boolean isToCitySelected() {
		return toCitySelected;
	}

	public void setToCitySelected(boolean toCitySelected) {
		this.toCitySelected = toCitySelected;
	}

	public List<SelectItem> getCitySelectItemList() {
		return citySelectItemList;
	}

	public void setCitySelectItemList(List<SelectItem> citySelectItemList) {
		this.citySelectItemList = citySelectItemList;
	}

	public List<SelectItem> getFromSubCitySelectItemList() {
		return fromSubCitySelectItemList;
	}

	public void setFromSubCitySelectItemList(
			List<SelectItem> fromSubCitySelectItemList) {
		this.fromSubCitySelectItemList = fromSubCitySelectItemList;
	}

	public List<SelectItem> getToSubCitySelectItemList() {
		return toSubCitySelectItemList;
	}

	public void setToSubCitySelectItemList(List<SelectItem> toSubCitySelectItemList) {
		this.toSubCitySelectItemList = toSubCitySelectItemList;
	}

	public int getSelHours() {
		return selHours;
	}

	public void setSelHours(int selHours) {
		this.selHours = selHours;
	}

	public int getSelMins() {
		return selMins;
	}

	public void setSelMins(int selMins) {
		this.selMins = selMins;
	}

	public List<SelectItem> getHoursSelectItemList() {
		return hoursSelectItemList;
	}

	public void setHoursSelectItemList(List<SelectItem> hoursSelectItemList) {
		this.hoursSelectItemList = hoursSelectItemList;
	}

	public List<SelectItem> getMinsSelectItemList() {
		return minsSelectItemList;
	}

	public void setMinsSelectItemList(List<SelectItem> minsSelectItemList) {
		this.minsSelectItemList = minsSelectItemList;
	}

	public Date getReservationDate() {
		return reservationDate;
	}

	public void setReservationDate(Date reservationDate) {
		this.reservationDate = reservationDate;
	}

	public HtmlInputText getCompReservationCode() {
		return compReservationCode;
	}

	public void setCompReservationCode(HtmlInputText compReservationCode) {
		this.compReservationCode = compReservationCode;
	}

	public HtmlInputTextarea getCompPickupAddress() {
		return compPickupAddress;
	}

	public void setCompPickupAddress(HtmlInputTextarea compPickupAddress) {
		this.compPickupAddress = compPickupAddress;
	}

	public HtmlSelectOneMenu getCompFCity() {
		return compFCity;
	}

	public void setCompFCity(HtmlSelectOneMenu compFCity) {
		this.compFCity = compFCity;
	}

	public HtmlSelectOneMenu getCompTCity() {
		return compTCity;
	}

	public void setCompTCity(HtmlSelectOneMenu compTCity) {
		this.compTCity = compTCity;
	}

	public HtmlSelectOneMenu getCompFSCity() {
		return compFSCity;
	}

	public void setCompFSCity(HtmlSelectOneMenu compFSCity) {
		this.compFSCity = compFSCity;
	}

	public HtmlSelectOneMenu getCompTSCity() {
		return compTSCity;
	}

	public void setCompTSCity(HtmlSelectOneMenu compTSCity) {
		this.compTSCity = compTSCity;
	}

	public SelectInputDate getCompPickupDate() {
		return compPickupDate;
	}

	public void setCompPickupDate(SelectInputDate compPickupDate) {
		this.compPickupDate = compPickupDate;
	}

	public HtmlSelectOneMenu getCompHrs() {
		return compHrs;
	}

	public void setCompHrs(HtmlSelectOneMenu compHrs) {
		this.compHrs = compHrs;
	}

	public HtmlSelectOneMenu getCompMins() {
		return compMins;
	}

	public void setCompMins(HtmlSelectOneMenu compMins) {
		this.compMins = compMins;
	}

	public HtmlSelectOneMenu getCompSeats() {
		return compSeats;
	}

	public void setCompSeats(HtmlSelectOneMenu compSeats) {
		this.compSeats = compSeats;
	}

	public HtmlSelectOneMenu getCompLuggages() {
		return compLuggages;
	}

	public void setCompLuggages(HtmlSelectOneMenu compLuggages) {
		this.compLuggages = compLuggages;
	}

	public HtmlSelectOneMenu getCompType() {
		return compType;
	}

	public void setCompType(HtmlSelectOneMenu compType) {
		this.compType = compType;
	}

	public boolean isAm() {
		return am;
	}

	public void setAm(boolean am) {
		this.am = am;
	}

	public HtmlSelectOneRadio getCompAmPm() {
		return compAmPm;
	}

	public void setCompAmPm(HtmlSelectOneRadio compAmPm) {
		this.compAmPm = compAmPm;
	}

	public HtmlInputText getCompCustomerName() {
		return compCustomerName;
	}

	public void setCompCustomerName(HtmlInputText compCustomerName) {
		this.compCustomerName = compCustomerName;
	}

	public HtmlInputText getCompCustomerContact() {
		return compCustomerContact;
	}

	public void setCompCustomerContact(HtmlInputText compCustomerContact) {
		this.compCustomerContact = compCustomerContact;
	}
}
